package link.jfire.jnet.common.buffer;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Queue;
import link.jfire.baseutil.collection.StringCache;
import link.jfire.baseutil.reflect.ReflectUtil;
import sun.misc.Unsafe;

@SuppressWarnings("restriction")
public abstract class ByteBuf<T>
{
	protected int					capacity;
	protected int					writeIndex		= 0;
	protected int					maskWrite		= 0;
	protected int					maskRead		= 0;
	protected int					readIndex		= 0;
	protected T						memory;
	protected Queue<T>				host;
	protected volatile int			release			= UNRELEASE;
	public static final int			UNRELEASE		= 0;
	public static final int			RELEASE			= 1;
	public static final long		offset			= ReflectUtil.getFieldOffset("release", ByteBuf.class);
	public static final Unsafe		unsafe			= ReflectUtil.getUnsafe();
	protected static final char[]	DIGITS_LOWER	= { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
	
	public ByteBuf<?> maskRead()
	{
		maskRead = readIndex;
		return this;
	}
	
	public ByteBuf<?> resetRead()
	{
		readIndex = maskRead;
		return this;
	}
	
	public int readIndex()
	{
		return readIndex;
	}
	
	public ByteBuf<T> readIndex(int readIndex)
	{
		this.readIndex = readIndex;
		return this;
	}
	
	public ByteBuf<T> addReadIndex(int length)
	{
		readIndex += length;
		return this;
	}
	
	public ByteBuf<T> addWriteIndex(int length)
	{
		writeIndex += length;
		return this;
	}
	
	public int writeIndex()
	{
		return writeIndex;
	}
	
	public ByteBuf<?> maskWrite()
	{
		maskWrite = writeIndex;
		return this;
	}
	
	public ByteBuf<?> resetWrite()
	{
		writeIndex = maskWrite;
		return this;
	}
	
	public ByteBuf<T> writeIndex(int writeIndex)
	{
		this.writeIndex = writeIndex;
		return this;
	}
	
	public void release()
	{
		if (release == UNRELEASE && unsafe.compareAndSwapInt(this, offset, UNRELEASE, RELEASE))
		{
			readIndex = writeIndex = capacity = 0;
			if (host == null)
			{
				_release();
				return;
			}
			if (host != null)
			{
				host.offer(memory);
				memory = null;
			}
		}
	}
	
	protected abstract void _release();
	
	/**
	 * 返回该ByteBuf的ByteBuffer视图。该视图的position为readIndex，limit为writeIndex。
	 * 视图当前处于可读状态
	 * 注意:
	 * 该视图与ByteBuf共享存储。
	 * 双方操作的修改是互相可见的。
	 * 但是ByteBuffer中的position和limit与ByteBuf中的readIndex和writeIndex互相不干扰。
	 * 
	 * @return
	 */
	public abstract ByteBuffer nioBuffer();
	
	/**
	 * 将buffer的内容放入数组中,该操作会改变buffer的position位置
	 * 
	 * @param buffer
	 */
	public void putByteBuffer(ByteBuffer buffer, int length)
	{
		int newCount = writeIndex + length;
		ensureCapacity(newCount);
		_putByteBuffer(buffer, length);
		writeIndex = newCount;
	}
	
	/**
	 * 具体子类实现的写入
	 * 
	 * @param buffer
	 * @param writeIndex
	 * @param length
	 */
	protected abstract void _putByteBuffer(ByteBuffer buffer, int length);
	
	/**
	 * 将一个byte放入缓存类中
	 * 
	 * @param b
	 */
	public void writeByte(byte b)
	{
		int newCount = writeIndex + 1;
		ensureCapacity(newCount);
		_writeByte(writeIndex, b);
		writeIndex = newCount;
	}
	
	protected abstract void _writeByte(int offset, byte b);
	
	public abstract void writeByte(int index, byte b);
	
	/**
	 * 将一个byte数组加入到缓存内容中
	 * 
	 * @param content
	 * @return
	 */
	public ByteBuf<T> put(byte[] content)
	{
		return put(content, 0, content.length);
	}
	
	public ByteBuf<T> put(byte[] content, int off, int len)
	{
		int newCount = writeIndex + len;
		ensureCapacity(newCount);
		_put(content, off, len);
		writeIndex = newCount;
		return this;
	}
	
	protected abstract void _put(byte[] content, int off, int len);
	
	/**
	 * 确定缓存的剩余容量是否能满足参数需求的大小。如果不能，自动扩容到当前容量+参数容量的两倍
	 * 
	 * @param sizeneed
	 * @return
	 */
	public ByteBuf<T> ensureCapacity(int newSize)
	{
		if (capacity < newSize)
		{
			_expend(capacity);
		}
		return this;
	}
	
	/**
	 * 将byteBuf扩容到指定的大小
	 * 
	 * @param capacity
	 */
	protected abstract void _expend(int size);
	
	/**
	 * 清除cache，将count和start同时设置为0
	 * 
	 * @return
	 */
	public ByteBuf<T> clear()
	{
		writeIndex = 0;
		readIndex = 0;
		return this;
	}
	
	/**
	 * 获取index位置的值。此操作不影响缓存内部状态
	 * 
	 * @param index
	 * @return
	 */
	public abstract byte get(int index);
	
	/**
	 * 获取接下里的一个值，此操作将缓存的readIndex加1
	 * 
	 * @return
	 */
	public abstract byte get();
	
	/**
	 * 返回当前的缓存总量
	 * 
	 * @return
	 */
	public int size()
	{
		return capacity;
	}
	
	/**
	 * 获取剩余的可读字节数
	 * 
	 * @return
	 */
	public int remainRead()
	{
		return writeIndex - readIndex;
	}
	
	/**
	 * 获取剩余的可写字节数
	 * 
	 * @return
	 */
	public int remainWrite()
	{
		return capacity - writeIndex;
	}
	
	/**
	 * 将缓存内剩余的字节构造成一个数组并且返回。但是不影响缓存内的参数
	 * 
	 * @return
	 */
	public abstract byte[] toArray();
	
	/**
	 * 将readIndex和writeIndex之间的部分移动到数组最开始的地方，此时readIndex为0，writeIndex是writeIndex
	 * -readIndex的值
	 */
	public abstract ByteBuf<T> compact();
	
	/**
	 * 从bytebuf中读取length长度的内容到content中
	 * 
	 * @param content 接受数据的byte数组
	 * @param length 需要接受的长度
	 */
	public void get(byte[] content, int length)
	{
		if (length > remainRead())
		{
			throw new RuntimeException("需要读取的长度太长，没有足够的数据可以读取");
		}
		else
		{
			_get(content, length);
		}
	}
	
	/**
	 * 从bytebuf中读取length长度的内容到byte数组中
	 * 
	 * @param content
	 * @param length
	 */
	protected abstract void _get(byte[] content, int length);
	
	/**
	 * 从当前位置开始，读取长度为length的字节，以charset编码转化为string并返回。
	 * cache的start位置前进length长度
	 * 
	 * @param charset
	 * @param length
	 * @return
	 * @author windfire(windfire@zailanghua.com)
	 */
	public abstract String toString(Charset charset, int length);
	
	/**
	 * 从当前位置开始，读取剩下的所有字节，按照charset组装成string并返回
	 * 此时cache中无可读字节
	 * 
	 * @param charset
	 * @return
	 */
	public String toString(Charset charset)
	{
		return toString(charset, remainRead());
	}
	
	/**
	 * 返回一个字符串描述当前的cache状态
	 */
	public String toString()
	{
		return new StringCache("readIndex:").append(readIndex).appendComma().append("writeIndex:").append(writeIndex).appendComma().append("capacity:").append(capacity).toString();
	}
	
	/**
	 * 将一个bytebuf的内容放入自身中,该操作不影响入参ByteBuf的内部参数
	 * 
	 * @param byteBuf
	 * @return
	 */
	public ByteBuf<T> put(ByteBuf<?> byteBuf)
	{
		return put(byteBuf, byteBuf.remainRead());
	}
	
	/**
	 * 将一个bytebuf的length长度的内容放入到本bytebuf中。该操作不影响入参bytebuf的readIndex和writeIndex
	 * 
	 * @param byteBuf
	 * @param length
	 * @return
	 */
	public ByteBuf<T> put(ByteBuf<?> byteBuf, int length)
	{
		int newWriteIndex = writeIndex + length;
		ensureCapacity(newWriteIndex);
		_put(byteBuf, length);
		writeIndex = newWriteIndex;
		return this;
	}
	
	/**
	 * 将一个bytebuf的length长度的内容放入到本bytebuf中。该操作不影响入参bytebuf的readIndex和writeIndex
	 * 
	 * @param byteBuf
	 * @param length
	 */
	protected abstract void _put(ByteBuf<?> byteBuf, int length);
	
	/**
	 * 写入一个int数据
	 * 
	 * @param i
	 * @return
	 */
	public ByteBuf<?> writeInt(int i)
	{
		int newWriteIndex = writeIndex + 4;
		ensureCapacity(newWriteIndex);
		_writeInt(writeIndex, i);
		writeIndex = newWriteIndex;
		return this;
	}
	
	public ByteBuf<?> writeInt(int index, int i)
	{
		_writeInt(index, i);
		return this;
	}
	
	protected abstract void _writeInt(int index, int i);
	
	public ByteBuf<?> writeShort(short s)
	{
		int newWriteIndex = writeIndex + 2;
		ensureCapacity(newWriteIndex);
		_writeShort(writeIndex, s);
		writeIndex = newWriteIndex;
		return this;
	}
	
	public ByteBuf<?> writeShort(int index, short s)
	{
		_writeShort(index, s);
		return this;
	}
	
	protected abstract void _writeShort(int index, short s);
	
	public ByteBuf<?> writeLong(long l)
	{
		int newWriteIndex = writeIndex + 8;
		ensureCapacity(newWriteIndex);
		_writeLong(writeIndex, l);
		writeIndex = newWriteIndex;
		return this;
	}
	
	public ByteBuf<?> writeLong(int index, long l)
	{
		_writeLong(index, l);
		return this;
	}
	
	protected abstract void _writeLong(int index, long l);
	
	public ByteBuf<?> writeFloat(float f)
	{
		return writeInt(Float.floatToRawIntBits(f));
	}
	
	public ByteBuf<?> writeFloat(int index, float f)
	{
		return writeInt(index, Float.floatToRawIntBits(f));
	}
	
	public ByteBuf<?> writeDouble(double d)
	{
		return writeLong(Double.doubleToRawLongBits(d));
	}
	
	public ByteBuf<?> writeDouble(int index, double d)
	{
		return writeLong(index, Double.doubleToRawLongBits(d));
	}
	
	public ByteBuf<?> writeChar(char c)
	{
		int newWriteIndex = writeIndex + 2;
		ensureCapacity(newWriteIndex);
		_writeChar(writeIndex, c);
		writeIndex = newWriteIndex;
		return this;
	}
	
	public ByteBuf<?> writeChar(int index, char c)
	{
		return writeChar(c);
	}
	
	protected abstract void _writeChar(int index, char c);
	
	public ByteBuf<?> writeBoolean(boolean b)
	{
		int newWriteIndex = writeIndex + 1;
		ensureCapacity(newWriteIndex);
		_writeBoolean(writeIndex, b);
		writeIndex = newWriteIndex;
		return this;
	}
	
	protected abstract void _writeBoolean(int index, boolean b);
	
	public abstract int readInt();
	
	public abstract int readInt(int index);
	
	public abstract short readShort();
	
	public abstract short readShort(int index);
	
	public abstract long readLong();
	
	public abstract long readLong(int index);
	
	public abstract char readChar();
	
	public abstract char readChar(int index);
	
	public abstract float readFloat();
	
	public abstract float readFloat(int index);
	
	public abstract double readDouble();
	
	public abstract double readDouble(int index);
	
	public abstract boolean readBoolean();
	
	public void writeString(String str, Charset charset)
	{
		if (str == null)
		{
			writeInt(-1);
		}
		else
		{
			byte[] content = str.getBytes(charset);
			writeInt(content.length);
			put(content);
		}
	}
	
	public String readString(Charset charset)
	{
		if (charset == null)
		{
			return null;
		}
		int length = readInt();
		if (length == -1)
		{
			return null;
		}
		byte[] src = new byte[length];
		get(src, length);
		return new String(src, charset);
	}
	
	/**
	 * 匹配对src在bytebuf中的位置。如果匹配，就返回最开始的位置，如果不匹配，返回-1
	 * 
	 * @param src
	 * @return
	 */
	public int indexOf(byte[] src)
	{
		int length = src.length;
		next: for (int i = readIndex; i < writeIndex; i++)
		{
			if (get(i) == src[0] && i + length < writeIndex)
			{
				for (int j = 0; j < length; j++)
				{
					if (get(i + j) == src[j])
					{
						
					}
					else
					{
						continue next;
					}
				}
				return i;
			}
		}
		return -1;
	}
	
	/**
	 * 返回buf当前的十六进制内容。该操作不会影响读写指针位置
	 * 
	 * @return
	 */
	public abstract String hexString();
}
